Skip to content

Add WinGet COM API backend with runtime selection + eight COM-backed features#7

Merged
harder merged 18 commits into
mainfrom
feat/com-backend
May 29, 2026
Merged

Add WinGet COM API backend with runtime selection + eight COM-backed features#7
harder merged 18 commits into
mainfrom
feat/com-backend

Conversation

@harder

@harder harder commented May 29, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a WinGet COM API backend (Microsoft.Management.Deployment) alongside the existing CLI and mock backends, plus eight UX features built on capabilities the COM API exposes that CLI stdout-parsing can't (or can only do badly). The COM backend returns structured objects instead of parsing winget.exe tabular output — no truncated IDs, no locale/encoding scraping, real progress and cancellation.

Backend is selectable at runtime (--mock / --cli / --com), defaulting to COM on Windows, CLI elsewhere.

⚠️ Verification status: developed on Linux/WSL, where Native AOT can't cross-compile and the WinGet COM server / installs don't exist. Everything builds (both TFMs), all tests pass, and Windows-TFM trim analysis is clean (0 IL2026/IL3050), but runtime behavior must be confirmed on Windows — see WINDOWS-TESTING.md, a P0/P1/P2 checklist shipped in this PR.

Why COM (the spike)

Before writing the backend, spikes/ComBackendSpike/ validated AOT readiness on a real Windows host. Key finding: never foreach/LINQ over a WinRT-projected collection under Native AOT — the IIterable<T> runtime-callable-wrapper isn't generated, so enumeration throws InvalidCastException. Indexed access (IVectorView.GetAt) works. The whole backend funnels projected collections through a Materialize<T>() helper that copies via indexing; ordinary foreach/LINQ then runs on the managed copy. The CsWinRT AOT optimizer was tried and did not fix the enumeration path, so it's intentionally not referenced — the dependency footprint is just Microsoft.WindowsPackageManager.ComInterop. Full writeup in spikes/ComBackendSpike/SPIKE-RESULTS.md.

Architecture

  • Multi-targeted project: net10.0 (cross-platform; mock/CLI dev loop on Linux) + net10.0-windows10.0.26100.0 (the Windows deploy target, which adds COM). ComBackend.cs, the ComInterop package, and a WINGET_COM compile constant are scoped to the Windows TFM via csproj conditions; on net10.0 the file compiles to nothing. Windows publish: dotnet publish -f net10.0-windows10.0.26100.0 -r win-x64.
  • Runtime backend gate (Program.cs): precedence --mock > --cli > --com > default; COM activation failure degrades to CLI rather than crashing.
  • Everything flows through the existing IBackend abstraction so the three backends stay swappable; CLI/mock degrade gracefully for COM-only features.

Features

# Feature Key Notes
1 Live install progress Structured InstallProgress/DownloadProgress/UninstallProgress → a determinate status-bar bar with phase labels (Downloading → Installing → …).
2 Cancel in-flight operations Esc Cooperative COM IAsyncInfo.Cancel() (CLI can only orphan/kill the process).
3 Install preview dialog i GetApplicableInstaller → confirm shows MSI · x64 · machine · admin (type/arch/scope/elevation). (COM exposes no download size, so size is intentionally omitted.)
4 Real version picker I AvailableVersions → selectable list instead of free-text (CLI falls back to free-text).
5 Download-only d DownloadPackageAsync fetches the installer without installing, reusing the progress bar + cancel.
6 Advanced install options A Scope / mode / architecture / custom args panel → InstallOptions (CLI → winget flags).
7 Verify install V CheckInstalledStatusAsync flags broken files/registration (corrupt-install detection). No CLI equivalent.
8 Richer detail panel Tags, Product code, Family name, Support + Documentation links from the manifest.

Cross-backend behavior

ComBackend (Windows) CliBackend MockBackend
Search / list / show / install / upgrade / uninstall structured COM winget.exe + parse fixtures
Progress + cancel real n/a (orphans process) simulated ramp
Preview / versions / verify real degrade (null / free-text / null) representative fakes
Pinning delegates to winget.exe (no COM pin API) native in-memory
Advanced options InstallOptions winget flags echoed

Review & quality

Each feature was followed by a read-only GitHub Copilot CLI review (inline-diff, no autonomous tooling); findings were triaged with judgment — valid ones fixed (e.g. an operation-progress race, a version-preview fallback bug, verify falsely reporting "clean" on partial COM reads), false positives rejected with evidence (e.g. ListView.SelectedItem is int? in this Terminal.Gui build), and untestable-from-Linux concerns documented as known limitations. The fix: commits are these review passes.

Known limitations (documented in ComBackend.cs)

  • Shared PackageManager across background threads assumes COM agility — verify no RPC_E_WRONG_THREAD on Windows.
  • All-or-nothing composite connect: an unhealthy msstore source can fail an All query (workaround: f to narrow source).
  • By-id operation resolution picks the first match across sources (matches CLI behavior).
  • Pinning needs winget.exe on PATH even on the COM backend.

Stats

~2,350 insertions across the app + ~600 in the spike. 12 feat/fix commits + 4 spike commits.

Test plan

  • net10.0 builds on Linux; net10.0-windows10.0.26100.0 builds via EnableWindowsTargeting
  • dotnet test green (parser tests unaffected)
  • Windows-TFM trim analysis: 0 IL2026/IL3050
  • Windows runtime — work through WINDOWS-TESTING.md (P0 foundational → P1 features → P2 edges)

🤖 Generated with Claude Code

harder and others added 16 commits May 27, 2026 19:05
Standalone console project that exercises the smallest end-to-end path
through the WinGet COM API (PackageManager → ConnectAsync → FindPackages
with PackageMatchFilter → CatalogPackage property access). Goal is to
catch the AOT-blocking warnings before committing to a full ComBackend
implementation.

Findings (full writeup in spikes/ComBackendSpike/SPIKE-RESULTS.md):

  - Trim analysis from Linux cross-compile shows 0 IL2026 and 0 IL3050
    warnings — the two categories that historically block CsWinRT
    adoption in AOT-published apps.
  - 35 IL2081 warnings all originate from CsWinRT marshaler fallback
    paths (ABI.System.Collections.Generic.*, ABI.Windows.Foundation.*,
    WinRT.Marshaler<>). Zero warnings originate from the
    Microsoft.Management.Deployment surface itself.
  - The COM projection requires net*-windows10.0.26100.0 TFM; consuming
    project must pick a Windows TFM (or multi-target).
  - InProcCom package is ~440MB extracted; only needed when bundling
    the OOP COM server. Standard winget installations don't require it.
  - Cross-OS Native AOT is not supported by ilc, so the final
    `PublishAot=true` codegen and runtime smoke must be done on Windows.
    Compile-time gates pass; runtime gates remain.

Verdict: green light to build the real ComBackend on this branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lets the AOT publish + smoke run be invoked from any directory by
absolute path. Wraps the publish/run sequence with cleaner output,
parameters for query/RID, and a -SkipPublish flag for rerunning the
already-built binary.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ions

First Windows AOT run proved codegen + COM activation work (3 catalogs
returned) but threw InvalidCastException in IReadOnlyListImpl.GetEnumerator
the moment we foreach'd a projected IReadOnlyList<T>: the IIterable<T> RCW
factory for that generic instantiation must be generated in the consuming
app, and ComInterop ships only the WinRT.Runtime runtime, not the CsWinRT
source generator.

Fix (ComBackendSpike.csproj):
- reference Microsoft.Windows.CsWinRT 2.2.0 (matches WinRT.Runtime in graph)
  so the AOT optimizer source generator runs
- CsWinRTAotOptimizerEnabled=Auto, AllowUnsafeBlocks=true
- CsWinRTGenerateProjection=false so it consumes ComInterop's prebuilt
  projection instead of re-running cswinrt.exe over the winmd
- CsWinRTRcwFactoryFallbackGeneratorForceOptIn=true — the by-name knob that
  generates RCW factories for projected types consumed under AOT

Program.cs rewritten as a two-lever diagnostic: Probe<T>() traverses each
projected collection via foreach (IIterable<T>) and, on failure, via indexed
access (IVectorView.GetAt), reporting which survives AOT — so one Windows run
yields a decision table instead of a crash.

Verified as far as a non-Windows host allows: restore (no version skew),
compile, and WinRT.SourceGenerator running with ForceOptIn flowing to the
compiler. Runtime confirmation pending a Windows re-run of Run-AotSpike.ps1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…optimizer

Windows runtime result: even with Microsoft.Windows.CsWinRT 2.2.0 +
CsWinRTRcwFactoryFallbackGeneratorForceOptIn=true wired in and confirmed
reaching the compiler, `foreach` over a projected IReadOnlyList<T> still
throws InvalidCastException under AOT for both catalogs and matches — the
IIterable<T> generic-instantiation RCW is not generated for this third-party
projection. Indexed access (IVectorView.GetAt) works perfectly with no
optimizer at all (same surface as .Count, which worked in the very first run).

So the optimizer package earned nothing: removed it and all four CsWinRT
properties + AllowUnsafeBlocks. Final recipe is just the ComInterop reference
plus index-based loops over WinRT collections. SPIKE-RESULTS.md updated with
the decision table, the Materialize<T> helper pattern for the real backend,
and the corrected verdict. Compile-clean on Linux with no cswinrt.exe in the
graph; runtime behavior validated on Windows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implements ComBackend (IBackend over the WinGet COM API) as a third backend
alongside CliBackend and MockBackend, selectable at runtime, plus the build
plumbing to ship it only where it can exist.

Structure:
- Main project now multi-targets net10.0 (cross-platform; mock/CLI) and
  net10.0-windows10.0.26100.0 (adds COM). ComBackend.cs + the ComInterop
  package + the WINGET_COM compile constant are scoped to the Windows TFM via
  csproj conditions; on net10.0 the file compiles to nothing so the Linux/mac
  dev loop is unaffected. EnableWindowsTargeting lets the Windows TFM build
  from a non-Windows host. Windows publish now needs
  -f net10.0-windows10.0.26100.0 (README updated).
- Also fixes a pre-existing breakage: the root project globbed spikes/** into
  the main compile; now excluded alongside tests/**.

ComBackend:
- Search/Installed/Upgrades via composite catalogs (RemotePackagesFromRemote
  for search, LocalCatalogs for installed/upgrades); Show reads
  CatalogPackageMetadata; Install/Upgrade/Uninstall via the PackageManager
  async ops with status->OpResult mapping.
- AOT rule from the spike honored throughout: never foreach a WinRT-projected
  collection (IIterable<T> RCW isn't generated under AOT). All projected lists
  go through Materialize<T>(), which copies via indexed IVectorView.GetAt.
  Trim analysis on the Windows TFM: 0 IL2026/IL3050.
- No COM pin API, so Pin/Unpin/ListPins delegate to an internal CliBackend
  (winget.exe is always present where the COM server is) — keeps full parity.
- HRESULT ExtendedErrorCode projects to System.Exception in this projection;
  HResultOf() pulls the numeric code back out for error messages.

Runtime selection (Program.cs): --mock/-m, --cli, --com; default is COM on
the Windows build, CLI elsewhere; both degrade to mock if winget is unusable.
COM activation failure is caught and falls back to CLI rather than crashing.

Verified: net10.0 builds + tests pass on Linux; Windows TFM compiles and
trim-analyzes clean via EnableWindowsTargeting. Live COM runtime still to be
exercised on Windows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Threads structured operation progress from the backend to the status bar via
an IProgress<OpProgress> parameter on InstallAsync/UpgradeAsync/UninstallAsync.

- Models: OpPhase (Queued/Downloading/Installing/Finalizing/Done) + OpProgress
  (phase + 0..1 fraction), both cross-platform.
- ComBackend: sets the WinRT op's .Progress handler before awaiting and maps
  InstallProgress / UninstallProgress (state + Download/Installation fraction)
  onto OpProgress. The handler fires on a COM thread; UiProgress marshals it.
- MockBackend: synthesizes a download->install ramp so the progress UI is
  visible/testable on any host (no Windows needed). CliBackend ignores progress
  (winget.exe only emits an ANSI bar we don't scrape).
- StatusBar: renders a determinate bar (▕████░░░░░░▏  42%  Installing X) with the
  phase label, replacing the spinner while an op runs.
- App: RunOperation builds a UiProgress that App.Invoke-marshals reports to the
  UI thread; OnOpProgress ignores late reports after the op settles. Batch
  upgrade passes null (the loop owns its own per-item status line).

Verified: both TFMs build, tests pass, Windows-TFM trim analysis still 0
IL2026/IL3050 (the .Progress delegate-callback marshaling rides the same CCW
path the spike's awaited ConnectAsync already exercised under AOT). Live COM
progress to be confirmed on Windows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The progress plumbing already forwarded a token to the COM op's AsTask(ct)
(which calls IAsyncInfo.Cancel cooperatively), but the UI passed
CancellationToken.None and had no cancel gesture. This wires it up.

- App owns a nullable _opCts; non-null = an operation is in flight (distinct
  from _viewCts/_detailCts, which cover list/detail refreshes). RunOperation
  creates it, passes its token to the op, and refuses to start a second op
  while one runs (avoids a leaked CTS and an ambiguous cancel target).
- Esc is split out of the shared Q/Esc quit case: while an op runs it cancels
  the op (and shows "Cancelling…") instead of quitting; otherwise unchanged.
- OperationCanceledException is caught distinctly -> "Cancelled" (not an error),
  and the list still refreshes since state may have partially changed.
- Batch upgrade shares the same _opCts: Esc aborts the in-flight item via its
  token and the loop stops on the next iteration.
- Status activity text advertises "· Esc to cancel" while running.

Cross-backend: COM cancels cooperatively; mock's simulated ramp honors the
token; CLI stops awaiting but does not kill winget.exe (unsafe mid-install).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Gate op-progress reports on _opCts (the precise "operation in flight" signal)
  instead of _state.Loading, which is also toggled by ordinary list/detail
  refreshes — closes a race where a concurrent refresh could drop progress
  samples or let a late report through after the op settled.
- Skip malformed package rows in Search/Installed/Upgrades instead of letting a
  bad HRESULT on a single Id/Name read tear down the whole listing.
- Add an Uninstalling phase so the status bar no longer says "Installing" during
  an uninstall.

Documented two deferred findings as known limitations in ComBackend's header:
all-or-nothing composite connect (mitigated by the 'f' source filter) and
by-id-only operation resolution (matches CliBackend; needs an IBackend change
to carry source identity). Both left as-is rather than ship untested COM
connection-probing or an interface change that a Linux build can't verify.

Both TFMs build, tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Backend gate/switch (Program.cs):
- --cli now takes precedence over --com: COM is chosen only when --cli was not
  passed (was: --com won even alongside --cli, contradicting the documented
  order). Precedence is now --mock > --cli > --com > default.
- Reworded the selection comment: flags are preferences, not hard guarantees —
  an unavailable requested backend degrades with a stderr note (--com off-Windows
  → CLI; CLI with no winget → mock). Behavior unchanged (graceful fallback is
  right for an interactive TUI); the docs just no longer claim "force".

ComBackend.cs:
- FindVersionId and ShowAsync now guard their COM property reads (AvailableVersions,
  vid.Version, pkg.Id/Name); a bad HRESULT yields "version not found" / a null
  detail (→ stub) instead of throwing, matching the list path's skip behavior.
- Unknown uninstall progress state maps to Uninstalling (was Installing).
- Upgrade failures now say "Upgrade failed" (DescribeInstall takes the verb).

Documented two untestable-from-Linux items as known limitations: the shared
PackageManager's thread-agility assumption (watch for RPC_E_WRONG_THREAD on
Windows) and that pin ops require winget.exe on PATH even on the COM backend.

Both TFMs build, tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…klist

Single P0/P1/P2 checklist of everything that can only be confirmed on Windows
(AOT can't cross-compile from Linux; the WinGet COM server and installs need
Windows): foundational COM runtime, search/list/upgrade/show, the operations,
the live progress bar (incl. the .Progress delegate CCW unknown), Esc
cancellation, and the review-flagged concerns (shared PackageManager thread
agility, unhealthy-source composite connect, pin-needs-winget, binary-size
measurement). Includes build/run commands and expected results per item.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two COM-backed UX upgrades, plumbed through IBackend so CLI/Mock degrade.

- IBackend gains ListVersionsAsync and GetInstallerPreviewAsync, plus an
  InstallerPreview model (installer type / architecture / scope / elevation +
  a "MSI · x64 · machine · admin" Summary). Note: the WinGet COM API exposes NO
  installer download size (BytesRequired is runtime-progress-only), so size is
  intentionally omitted rather than faked.
- ComBackend: ListVersions enumerates AvailableVersions (indexed/Materialize,
  newest-first, deduped); GetInstallerPreview resolves PackageVersionInfo (for
  the chosen or default version) and maps GetApplicableInstaller(InstallOptions)
  → InstallerPreview, with friendly enum mapping and full exception guarding.
- CliBackend degrades: empty version list (→ free-text fallback) and null
  preview (→ plain confirm). MockBackend returns representative data so both
  features are exercisable on Linux.
- UI: new VersionPickerDialog (ListView). App.AskInstall is now async:
  `i` → fetch preview → confirm showing the installer summary → install;
  `I` → fetch versions → picker (or free-text fallback) → preview confirm →
  install. A FetchThen<T> helper runs the short async fetch off-thread with a
  transient status, then marshals the modal onto the UI thread.

Both TFMs build, tests pass, Windows-TFM trim analysis 0 IL2026/IL3050.
WINDOWS-TESTING.md updated with preview/picker verification items.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…gate

- GetInstallerPreviewAsync no longer falls back to the installed version when a
  SPECIFIC version was requested but couldn't be resolved (that produced a
  preview computed from the wrong installer while the confirm said "Install X
  <version>"). Explicit version → resolve exactly or return null; latest →
  default-install else installed.
- FetchThen now serializes preflight fetches via a _preflightBusy gate, so a
  rapid second trigger can't queue a duplicate modal or race the status line.

Rejected from the review: the claim that ListView.SelectedItem is `int` (it's
`int?` in Terminal.Gui 2.4.3-develop.9 — the build proves it; `?? -1` stays).
Other low items (picker empty-list defensiveness, PickVersion using-dispose)
left to match existing dialog patterns / caller contract.

Both TFMs build, tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two more COM-backed operations, plumbed through IBackend (CLI maps to winget
flags, mock simulates).

Download-only ('d'):
- IBackend.DownloadAsync; ComBackend uses DownloadPackageAsync(DownloadOptions)
  into %USERPROFILE%\Downloads\winget-tui, mapping PackageDownloadProgress onto
  the existing OpProgress bar; CLI runs `winget download -d <dir>`; mock ramps a
  download. Reuses RunOperation, so the progress bar + Esc-cancel work for free.

Advanced install ('A'):
- InstallSettings model (scope / mode / arch / custom args). InstallAsync gains
  an InstallSettings? param across the interface + all three backends.
- ComBackend maps it onto InstallOptions (PackageInstallScope, PackageInstallMode,
  AllowedArchitectures.Add, AdditionalInstallerArguments); CLI maps to --scope /
  --silent|--interactive / --architecture / --custom; mock echoes it.
- New AdvancedInstallDialog (OptionSelector x3 + args field) gathers settings;
  the install confirm shows an "Options: …" line alongside the installer preview.

InstallArgs keeps a default settings=null param so existing parser tests are
unaffected. OperationKind += Download. Help text + WINDOWS-TESTING.md updated.

Both TFMs build, tests pass, Windows-TFM trim analysis 0 IL2026/IL3050.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Advanced install: normalize an all-default selection to null ("backend
  defaults") via InstallSettings.IsDefault, so it behaves identically to a plain
  install on every backend instead of passing a no-op settings object. (The
  underlying COM-forces-silent default is pre-existing and unchanged.)
- Download: stop swallowing Directory.CreateDirectory failures. Both COM and CLI
  now fail fast with a clear "could not prepare download folder" message instead
  of degrading into a more obscure winget/COM error later.

Kept (Low): the AdvancedInstallDialog enum-by-index cast — the alignment is
documented and an unexpected value degrades safely to Default; explicit map
arrays weren't worth the churn.

Both TFMs build, tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Verify install ('V'):
- IBackend.VerifyInstalledAsync; ComBackend maps CheckInstalledStatusAsync
  (InstalledStatusType.AllChecks) onto an InstallVerification (Ok / Issues /
  NotApplicable / Error + per-check list). Traverses the nested projected
  vectors (PackageInstalledStatus → InstallerInstalledStatus) via Materialize
  (AOT rule); an InstalledStatus whose HRESULT projects to a null Exception =
  S_OK = passed. CLI returns null (no equivalent); mock fakes Ok/Issues.
- UI: 'V' runs the check via FetchThen and shows a ✓/✗ result MessageBox; the
  detail panel and help advertise it.

Richer detail panel:
- PackageDetail gains Tags, SupportUrl, Documentation (DocLink list),
  ProductCodes, PackageFamilyNames. ComBackend.ShowAsync fills them from
  CatalogPackageMetadata (Tags/Documentations/PublisherSupportUrl) and
  PackageVersionInfo (ProductCodes/PackageFamilyNames) via guarded indexed
  reads. DetailPanel renders Tags/identifiers as KV lines and Support/Docs as
  clickable link rows; absent fields are omitted (no empty rows). Mock supplies
  representative values; CLI leaves them null.

Both TFMs build, tests pass, Windows-TFM trim analysis 0 IL2026/IL3050.
Help + WINDOWS-TESTING.md updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
VerifyInstalledAsync hardening:
- Track hadReadError across the nested COM reads; if any installer/entry read
  throws, don't report Ok/NotApplicable (which would falsely call a partially-
  read install "clean") — report Error.
- Wrap the result.Status / PackageInstalledStatus traversal in a guard so a
  throwing getter/materialization maps to VerifyOutcome.Error instead of leaking.
- Stop overloading null: a not-found/not-installed package now returns
  NotApplicable; null is reserved for "backend can't verify" (CLI), so the UI's
  "only on the COM backend" message is no longer shown for a Windows lookup miss.

DocLinks: per-element try/catch so one malformed Documentation entry is skipped
instead of dropping the whole documentation list.

Both TFMs build, tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 29, 2026 15:36

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new Windows-only WinGet COM API backend alongside the existing CLI/mock backends, adds runtime backend selection, and extends the UI/UX to support COM-only capabilities like structured progress, cancellation, version picking, download-only, advanced install options, verification, and richer manifest details.

Changes:

  • Multi-target the app (net10.0 + net10.0-windows10.0.26100.0) and add a Windows-TFM-only COM backend (plus runtime backend selection via --mock/--cli/--com).
  • Extend IBackend with progress-aware operations and new COM-enabled capabilities (version listing, installer preview, download-only, verify install), with CLI/mock graceful degradation.
  • Add UI elements for live progress + cancel (Esc), version picker, advanced install dialog, download-only action, verify action, and richer detail panel fields; add Windows verification checklist and a spike project documenting AOT constraints.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
WingetTuiSharp.csproj Multi-targeting + Windows-only COM dependency/constant; exclude spikes from main compile globs.
WINDOWS-TESTING.md New Windows runtime verification checklist for COM/AOT behavior and features.
src/Ui.cs Status bar determinate progress UI; version picker + advanced install dialogs; help text updates.
src/Models.cs New models/enums for progress, installer preview, advanced install settings, verify results, richer details.
src/MockBackend.cs Implement new IBackend surface (versions/preview/progress/download/verify) with simulated behavior.
src/GlobalUsings.cs Add global using for ObservableCollection (used by version picker).
src/DetailPanel.cs Render richer manifest fields (tags/product code/family name/support/docs) + add Verify action.
src/ComBackend.cs New WinGet COM API backend (Windows TFM only), including progress mapping, download, verify, installer preview, versions; pins delegated to CLI.
src/CliBackend.cs Extend CLI backend to satisfy new IBackend surface; add winget download and advanced install flag mapping; verify/versions/preview degrade.
src/Backend.cs Expand IBackend API for new COM-backed features and progress reporting.
src/AppState.cs Track in-flight operation progress in app state.
src/App.cs Wire new actions (download/advanced/verify/version picker), Esc-to-cancel, one-op-at-a-time gate, progress plumbing.
Program.cs Runtime backend selection logic with graceful degradation and precedence rules.
README.md Update build/run docs for multi-targeting and runtime backend selection; document COM backend behavior.
spikes/ComBackendSpike/SPIKE-RESULTS.md Document AOT findings and “index, don’t enumerate WinRT projections” constraint.
spikes/ComBackendSpike/Run-AotSpike.ps1 PowerShell helper to publish/run the spike under Native AOT on Windows.
spikes/ComBackendSpike/Program.cs Spike program probing COM + AOT enumeration failure modes and the indexing workaround.
spikes/ComBackendSpike/ComBackendSpike.csproj Spike project configuration mirroring AOT/trim settings and COM package reference.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/App.cs
harder and others added 2 commits May 29, 2026 11:36
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@harder harder merged commit 053f658 into main May 29, 2026
2 checks passed
@harder harder deleted the feat/com-backend branch May 29, 2026 19:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants